/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License.You may obtain a copy of the License at
	http://www.mozilla.org/MPL/MPL-1.1.html
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/
 
/**
 * Provides basic mathematical methods.
 * 
 * @author Romain Ecarnot
 */
class fever.utils.MathUtils
{
	//------------------------------------------------------------------//
	// Public API
	//------------------------------------------------------------------//
	
	/**
	 * Converts passed-in {@code angle} angle in radian.
	 * 
	 * @param angle Angle in degree 
	 * @return Radian convertion
	 */ 
	public static function toRadian( angle : Number ) : Number
	{
		return (angle * Math.PI)/180;
	}
	
	/**
	 * Converts passed-in {@code angle} angle in degree.
	 * 
	 * @param angle Angle in radian
	 * @return Radian convertion
	 */ 
	public static function toDegre( angle : Number ) : Number
	{
		return ( angle * 180 )/Math.PI;
	}
	
	/**
	 * Round passed number with passed precision.
	 * 
	 * @param value Value to round
	 * @param digits Round precision 
	 * @return Rounde value of {@code value} with {@code digits} precision
	 */
	public static function round( value : Number, digits : Number ) : Number
	{
		return Math.round( value * Math.pow(10, digits)) / Math.pow(10, digits);
	}
	
	/**
	 * Returns random number between {@code firstvalue} and {@code secondvalue} value.
	 * 
	 * <p>Arguments are automaticcaly re-order.
	 * 
	 * @param firstvalue First interval limit
	 * @param secondvalue Second interval limit 
	 * @param rounded Indicates if result must be round or not
	 * @return Random number in {@code firstvalue} and {@code secondvalue} interval
	 */
	public static function random( firstvalue : Number, secondvalue : Number, rounded : Boolean ) : Number
	{ 
		var nMax : Number = Math.max( firstvalue, secondvalue );
		var nMin : Number = Math.min( firstvalue, secondvalue );
		var r : Number = ( Math.random()*( nMax - nMin ) + nMin );
		
		return ( rounded ) ? Math.round( r ) : r;
	}
	
	/**
	 * Returns square value of passed-in {@code value} value.
	 * 
	 * @param value Number 
	 * @return Square value of {@code value}
	 */
	public static function square( value : Number ) : Number
	{
		return ( value * value);
	}
	
	/**
	 * Returns inverse of passed-in {@code value} value
	 * 
	 * @param value Number 
	 * @return Inverse of {@code value} or '0' if {@code value == 0}
	 */
	public static function inverse( value : Number ) : Number
	{
		var n : Number = value >> 0;
		return (!n) ? 0 : ( 1 / n );
	}
	
	/**
	 * Calculates sum of elements passed in {@code array} instance.
	 * 
	 * @param array Values array
	 * @return {@code Number}
	 */
	public static function sum( array : Array ) : Number
	{
		var l : Number = array.length;
		var r : Number = 0;
		
		if(!l) return 0;
		
		while(--l > -1)	r += array[l];
		
		return r;
	}
	
	/**
	 * Calculates mean of elements passed in {@code array} instance.
	 * 
	 * @param a Values array 
	 * @return {@code Number}
	 */
	public static function mean( a : Array ) : Number
	{
		var nL : Number = a.length;		var l : Number = nL;
		var r : Number = 0;
		
		if(!l) return 0;
		
		while(--l > -1) r += a[l];
		
		return ( r / nL );
	}
	
	/**
	 * Calculates and returns the factorial of {@code n}
	 * 
	 * @param {@code Number}
	 */
	public static function factorial( n : Number) : Number
    {
        if ( n!=0 ) return n * factorial( n-1 );
        else return 1;
    }
	
	/**
	 * Returns percent value from passed-in {@code value} according 
	 * {@code total}.
	 * 
	 * <p>If result is not a number or is is infinite, returns {@code null}.
	 * 
	 * @param value Number to check
	 * @param total Reference number.
	 * @param rounded {@code true} to round the percent result
	 * 
	 * @return Percent value or {@code null}
	 */
	public static function percent( value : Number, total : Number, rounded : Boolean ) : Number
	{
		var n : Number = ( value / total ) * 100 ;
		return ( isNaN( n ) || !isFinite( n ) ) ? null : ( rounded ) ? Math.round( n ) : n ;
	}
	
	/**
	 * Calculates and returns the variance of elements in 
	 * passed-in {@code a} Array.
	 * 
	 * @param a Array with elements to check
	 * 
	 * @return {@code Number}
	 */
	public static function getVariance( a : Array ) : Number
	{
		var l : Number = a.length;
		var sum : Number = 0;
		var sqr : Number = 0;
		
		for( var i : Number = 0; i < l; i++ )
		{
			var n : Number = a[i];
			sum += n;
			sqr += ( n * n );
     	}
     
		var mean : Number = sum / l;
		return ( sqr / l ) - ( mean * mean );
	}
	
	/**
	 * Calculates and returns standart deviation of elements in 
	 * passed-in {@code a} Array.
	 * 
	 * @param a Array with elements to check
	 * 
	 * @return {@code Number}
	 */
	public static function getStandartDeviation( a : Array ) : Number
	{
		return Math.sqrt( getVariance( a ) );
	}
	
	
	//------------------------------------------------------------------//
	// Private implementation
	//------------------------------------------------------------------//
	
	private function MathUtils() {}
}